package com.hyts.keygen.handler;

import com.hyts.keygen.config.KeyWorkProperties;
import lombok.Getter;

/**
 * @project-name:coffice-toolbox
 * @package-name:com.hyts.keygen.handler
 * @author:Libo/Alex
 * @create-date:2019-05-25 00:53
 * @copyright:libo-hyts-github
 * @email:libo2dev@aliyun.com
 * @description:此类主要用于: keyworker 操作key生成器-工作任务组件
 */
public class KeyWorker {

    @Getter
    private long dataCenterId;

    @Getter
    private long workerId;

    @Getter
    private long sequence;

    @Getter
    private long lastTimestamp = KeyWorkProperties.DEAULT_LAST_TIME_STAMP;

    /**
     * 构造器
     * @param workerId 工作者ID
     * @param datacenterId 数据中心ID
     */
    public KeyWorker(long workerId, long datacenterId) {
        // sanity check for workerId
        if (workerId > KeyWorkProperties.DEFAULT_MAX_WORK_ID || workerId < 0) {
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", KeyWorkProperties.DEFAULT_MAX_WORK_ID));
        }
        if (datacenterId > KeyWorkProperties.DEFAULT_MAX_DATA_CENTER_ID || datacenterId < 0) {
            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", KeyWorkProperties.DEFAULT_MAX_DATA_CENTER_ID));
        }
        this.workerId = workerId;
        this.dataCenterId = datacenterId;
        //log.info(String.format("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d", timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId));
    }

    /**
     * 下一个id生产方法
     * @return
     */
    public synchronized long nextId() {
        long timestamp = KeyTimeHandler.generate();
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & KeyWorkProperties.DEFAULT_SEQUENCE_MASK;
            if (sequence == 0) {
                timestamp = KeyTimeHandler.generateNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }
        lastTimestamp = timestamp;
        return (timestamp << KeyWorkProperties.TIME_SAMPLE_ID_SHIFT) |
               (dataCenterId << KeyWorkProperties.DEFAULT_DATA_CENTER_SHIFT) |
               (workerId << KeyWorkProperties.DEFAULT_WORK_ID_SHIFT) | sequence;
    }

}
